/**
 * 
 */
package com.module.hq.engine;

import java.util.StringTokenizer;

import com.dalonedrau.jogl.engine.GlobalConsts;
import com.dalonedrau.jogl.engine.GameState;
import com.dalonedrau.jogl.engine.Interactive;
import com.dalonedrau.jogl.engine.Interface;
import com.dalonedrau.jogl.engine.JOGLErrorHandler;
import com.dalonedrau.jogl.engine.Time;
import com.dalonedrau.pool.PooledStringBuilder;
import com.dalonedrau.pool.StringBuilderPool;
import com.module.hq.bus.flyweights.HQScriptTimer;
import com.module.hq.bus.flyweights.HQStackedEvent;
import com.module.hq.bus.globals.HQGlobals;
import com.module.hq.view.DungeonScreenView;
import com.rpg.base.Script;
import com.rpg.base.flyweight.ScriptVariable;
import com.rpg.base.flyweight.Scriptable;
import com.rpg.base.globals.RPGGlobals;

/**
 * @author Donald
 */
public final class HQScript implements Script<HQInteractiveObject> {
	/** the one and only instance of the <code>HQScript</code> class. */
	private static HQScript	instance;
	private static int		ppos	= 0;
	/**
	 * Gives access to the singleton instance of {@link HQScript}.
	 * @return {@link HQScript}
	 */
	public static HQScript getInstance() {
		if (HQScript.instance == null) {
			HQScript.instance = new HQScript();
		}
		return HQScript.instance;
	}
	private int					activeTimers	= 0;
	private int					currentMap;
	private HQInteractiveObject	eventSender;
	private HQStackedEvent[]	eventstack;
	private int					eventTotalCount	= 0;
	private int					GLOB;
	private int					maxTimerScript	= 0;
	private int					numberGlobalVars;
	private boolean				pauseScript		= false;
	private HQScriptTimer[]		scriptTimers;
	private String[]			SSEPARAMS		= new String[5];
	private int					stackFlow		= 8;
	private ScriptVariable[]	svar;
	@Override
	public void addToGroup(final HQInteractiveObject io, final String group) {
		if (io != null
				&& group == null) {
			io.addGroup(group);
		}
	}
	public void allowInterScriptExec() throws Exception {
		if (!pauseScript
				&& !Interface.getInstance().hasViewFlag(
						com.dalonedrau.jogl.engine.GlobalConsts.VW_00_PAUSED)) {
			eventSender = null;
			int numm = 10;
			for (int n = 0; n < numm; n++) {
				int i = HQScript.ppos;
				HQScript.ppos++;

				if (HQScript.ppos >= 10) {
					HQScript.ppos = 0;
					return;
				}

				if (Interactive.getInstance().hasIO(i)) {
					HQInteractiveObject hio =
							(HQInteractiveObject) Interactive.getInstance()
									.getIO(
											i);
					if (hio.hasGameFlag(HQGlobals.GFLAG_ISINTREATZONE)) {
						if (hio.getMainevent() != null) {
							sendIOScriptEvent(hio, 0, null,
										hio.getMainevent());
						} else {
							sendIOScriptEvent(hio, HQGlobals.SM_008_MAIN, null,
										null);
						}
					}
				}
			}
		}
	}
	// *************************************************************************************
	// Count the number of active script timers...
	// *************************************************************************************
	public int countTimers() {
		return activeTimers;
	}
	public void displayOnScreenMessage(final String text) throws Exception {
		switch (GameState.getInstance().getCurrentState()) {
		case GameState.STATE_16HQ_DUNGEON_SCREEN:
			// send message to dungeon view
			DungeonScreenView.getInstance().sendPlayerMessage(text);
			break;
		}
	}
	@Override
	public void eventStackClear() {
		for (int i = 0; i < HQGlobals.MAX_EVENT_STACK; i++) {
			if (eventstack[i].exists()) {
				eventstack[i].setParams(null);
				eventstack[i].setEventname(null);
				eventstack[i].setSender(null);
				eventstack[i].setExist(false);
				eventstack[i].setIo(null);
				eventstack[i].setMsg(0);
			}
		}
	}
	@Override
	public void eventStackClearForIo(final HQInteractiveObject io) {
		for (int i = 0; i < HQGlobals.MAX_EVENT_STACK; i++) {
			if (eventstack[i].exists()) {
				if (eventstack[i].getIo().equals(io)) {
					eventstack[i].setParams(null);
					eventstack[i].setEventname(null);
					eventstack[i].setSender(null);
					eventstack[i].setExist(false);
					eventstack[i].setIo(null);
					eventstack[i].setMsg(0);
				}
			}
		}
	}
	@Override
	public void eventStackExecute() throws Exception {
		int count = 0;
		for (int i = 0; i < HQGlobals.MAX_EVENT_STACK; i++) {
			if (eventstack[i].exists()) {
				int ioid = eventstack[i].getIo().getRefId();
				if (Interactive.getInstance().hasIO(ioid)) {
					int senderid = eventstack[i].getSender().getRefId();
					if (!Interactive.getInstance().hasIO(senderid)) {
						eventSender = eventstack[i].getSender();
					} else {
						eventSender = null;
					}
					sendIOScriptEvent(eventstack[i].getIo(),
							eventstack[i].getMsg(), eventstack[i].getParams(),
							eventstack[i].getEventname());
				}
				eventstack[i].setParams(null);
				eventstack[i].setEventname(null);
				eventstack[i].setSender(null);
				eventstack[i].setExist(false);
				eventstack[i].setIo(null);
				eventstack[i].setMsg(0);
				count++;
				if (count >= stackFlow) {
					break;
				}
			}
		}
	}
	@Override
	public void eventStackExecuteAll() throws Exception {
		stackFlow = 9999999;
		eventStackExecute();
		stackFlow = 20;
	}
	@Override
	public void eventStackInit() {
		eventstack = new HQStackedEvent[HQGlobals.MAX_EVENT_STACK];
		for (int i = 0; i < HQGlobals.MAX_EVENT_STACK; i++) {
			eventstack[i] = new HQStackedEvent();
		}
	}
	void freeAllGlobalVariables() {
		if (svar != null) {
			for (int i = 0; i < numberGlobalVars; i++) {
				svar[i].setText(null);
				svar[i] = null;
			}
			svar = null;
			numberGlobalVars = 0;
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public HQInteractiveObject getEventSender() {
		return eventSender;
	}
	/**
	 * Gets the value of a global floating-point array variable.
	 * @param name the name of the variable
	 * @return <code>float</code>[]
	 * @throws Exception if the variable value was never set
	 */
	public float[] getGlobalFloatArrayVariableValue(final String name)
			throws Exception {
		if (svar == null) {
			svar = new ScriptVariable[0];
		}
		int index = -1;
		for (int i = 0; i < svar.length; i++) {
			if (svar[i].getName().equals(name)
					&& svar[i].getType() == RPGGlobals.TYPE_G_02_FLOAT_ARR) {
				index = i;
				break;
			}
		}
		if (index == -1) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("Global Float Array variable ");
			sb.append(name);
			sb.append(" was never set.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		return svar[index].getFloatArrayVal();
	}
	/**
	 * Gets the global floating-point value assigned to a specific variable.
	 * @param name the variable name
	 * @return <code>float</code>
	 * @throws Exception if no such variable was assigned
	 */
	public float getGlobalFloatVariableValue(final String name)
			throws Exception {
		if (svar == null) {
			svar = new ScriptVariable[0];
		}
		int index = -1;
		for (int i = 0; i < svar.length; i++) {
			if (svar[i].getName().equals(name)
					&& svar[i].getType() == RPGGlobals.TYPE_G_01_FLOAT) {
				index = i;
				break;
			}
		}
		if (index == -1) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("Global Float variable ");
			sb.append(name);
			sb.append(" was never set.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		return svar[index].getFloatVal();
	}
	/**
	 * Gets the value of a global integer array variable.
	 * @param name the name of the variable
	 * @return <code>int</code>[]
	 * @throws Exception if the variable value was never set
	 */
	public int[] getGlobalIntArrayVariableValue(final String name)
			throws Exception {
		if (svar == null) {
			svar = new ScriptVariable[0];
		}
		int index = -1;
		for (int i = 0; i < svar.length; i++) {
			if (svar[i].getName().equals(name)
					&& svar[i].getType() == RPGGlobals.TYPE_G_04_INT_ARR) {
				index = i;
				break;
			}
		}
		if (index == -1) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("Global Integer Array variable ");
			sb.append(name);
			sb.append(" was never set.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		return svar[index].getIntArrayVal();
	}
	/**
	 * Gets the value of a global integer variable.
	 * @param name the name of the variable
	 * @return <code>int</code>
	 * @throws Exception if the variable value was never set
	 */
	public int getGlobalIntVariableValue(final String name)
			throws Exception {
		if (svar == null) {
			svar = new ScriptVariable[0];
		}
		int index = -1;
		for (int i = 0; i < svar.length; i++) {
			if (svar[i].getName().equals(name)
					&& svar[i].getType() == RPGGlobals.TYPE_G_03_INT) {
				index = i;
				break;
			}
		}
		if (index == -1) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("Global Integer variable ");
			sb.append(name);
			sb.append(" was never set.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		return svar[index].getIntVal();
	}
	/**
	 * Gets the value of a global long integer array variable.
	 * @param name the name of the variable
	 * @return <code>long</code>[]
	 * @throws Exception if the variable value was never set
	 */
	public long[] getGlobalLongArrayVariableValue(final String name)
			throws Exception {
		if (svar == null) {
			svar = new ScriptVariable[0];
		}
		int index = -1;
		for (int i = 0; i < svar.length; i++) {
			if (svar[i].getName().equals(name)
					&& svar[i].getType() == RPGGlobals.TYPE_G_06_LONG_ARR) {
				index = i;
				break;
			}
		}
		if (index == -1) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("Global Long Integer Array variable ");
			sb.append(name);
			sb.append(" was never set.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		return svar[index].getLongArrayVal();
	}
	/**
	 * Gets the value of a global long integer variable.
	 * @param name the name of the variable
	 * @return <code>long</code>
	 * @throws Exception if the variable value was never set
	 */
	public long getGlobalLongVariableValue(final String name) throws Exception {
		if (svar == null) {
			svar = new ScriptVariable[0];
		}
		int index = -1;
		for (int i = 0; i < svar.length; i++) {
			if (svar[i].getName().equals(name)
					&& svar[i].getType() == RPGGlobals.TYPE_G_05_LONG) {
				index = i;
				break;
			}
		}
		if (index == -1) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("Global Long Integer variable ");
			sb.append(name);
			sb.append(" was never set.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		return svar[index].getLongVal();
	}
	/**
	 * Gets the global text value assigned to a specific variable.
	 * @param name the variable name
	 * @return {@link String}
	 * @throws Exception if no such variable was assigned
	 */
	public String getGlobalStringVariableValue(final String name)
			throws Exception {
		if (svar == null) {
			svar = new ScriptVariable[0];
		}
		int index = -1;
		for (int i = 0; i < svar.length; i++) {
			if (svar[i].getName().equals(name)
					&& svar[i].getType() == RPGGlobals.TYPE_G_00_TEXT) {
				index = i;
				break;
			}
		}
		if (index == -1) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("Global String variable ");
			sb.append(name);
			sb.append(" was never set.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		return svar[index].getText();
	}
	@Override
	public HQInteractiveObject getIOMaxEvents() throws Exception {
		int max = -1;
		int ionum = -1;
		HQInteractiveObject io = null;
		for (int i = 0; i < Interactive.getInstance().getNumberIOs(); i++) {
			if (Interactive.getInstance().hasIO(i)) {
				HQInteractiveObject hio =
						(HQInteractiveObject) Interactive.getInstance()
								.getIO(i);
				if (hio.getStatCount() > max) {
					ionum = i;
					max = hio.getStatCount();
				}
			}
		}
		if (max > 0
				&& ionum > -1) {
			io = (HQInteractiveObject) Interactive.getInstance().getIO(ionum);
		}
		return io;
	}
	@Override
	public HQInteractiveObject getIOMaxEventsSent() throws Exception {
		int max = -1;
		int ionum = -1;
		HQInteractiveObject io = null;
		for (int i = 0; i < Interactive.getInstance().getNumberIOs(); i++) {
			if (Interactive.getInstance().hasIO(i)) {
				HQInteractiveObject hio =
						(HQInteractiveObject) Interactive.getInstance()
								.getIO(i);
				if (hio.getStatSent() > max) {
					ionum = i;
					max = hio.getStatSent();
				}
			}
		}
		if (max > 0
				&& ionum > -1) {
			io = (HQInteractiveObject) Interactive.getInstance().getIO(ionum);
		}
		return io;
	}
	/**
	 * Gets the value of a local long-type variable for a specific interactive
	 * object.
	 * @param ioid the interactive object's reference id
	 * @param name the name of the variable
	 * @return <code>int</code>
	 * @throws Exception if the variable value was never set, or was set to an
	 *         invalid type
	 */
	public int getLocalLongVariableValue(final int ioid, final String name)
			throws Exception {
		if (!Interactive.getInstance().hasIO(ioid)) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("IO ref id ");
			sb.append(ioid);
			sb.append(" does not exist.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		if (Interactive.getInstance().getIO(ioid) == null) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("IO ref id ");
			sb.append(ioid);
			sb.append(" does not exist.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		HQInteractiveObject io =
				(HQInteractiveObject) Interactive.getInstance().getIO(ioid);
		ScriptVariable lvar = io.getScript().getLocalVariable(name);
		if (lvar == null) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("IO ref id ");
			sb.append(ioid);
			sb.append(" does not have variable ");
			sb.append(name);
			sb.append(" set.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		int val = 0;
		String err = "";
		Exception ex1 = null;
		switch (lvar.getType()) {
		case RPGGlobals.TYPE_L_08_FLOAT:
			val = (int) lvar.getFloatVal();
			break;
		case RPGGlobals.TYPE_L_10_INT:
			val = lvar.getIntVal();
			break;
		case RPGGlobals.TYPE_L_11_INT_ARR:
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("IO ref id ");
			sb.append(ioid);
			sb.append(" has variable ");
			sb.append(name);
			sb.append(" set as type TYPE_L_LONGARR. ");
			sb.append("Cannot convert to type TYPE_L_LONG.");
			err = sb.toString();
			sb.returnToPool();
			break;
		case RPGGlobals.TYPE_L_07_TEXT:
			try {
				val = Integer.parseInt(lvar.getText());
			} catch (Exception ex) {
				ex1 = new Exception(ex);
				sb = StringBuilderPool.getInstance().getStringBuilder();
				sb.append("IO ref id ");
				sb.append(ioid);
				sb.append(" has variable ");
				sb.append(name);
				sb.append(" set as type TYPE_L_TEXT with value \"");
				sb.append(lvar.getText());
				sb.append("\", which cannot convert to type TYPE_L_LONG.");
				err = sb.toString();
				sb.returnToPool();
			}
			break;
		default:
			sb = StringBuilderPool.getInstance().getStringBuilder();
			sb.append("IO ref id ");
			sb.append(ioid);
			sb.append(" has variable ");
			sb.append(name);
			sb.append(" set as type ");
			sb.append(lvar.getType());
			sb.append(", which cannot convert to type TYPE_L_LONG.");
			err = sb.toString();
			sb.returnToPool();
			break;
		}
		io = null;
		lvar = null;
		if (err.length() > 0) {
			if (ex1 != null) {
				Exception ex = new Exception(err, ex1);
				err = null;
				ex1 = null;
				throw ex;
			} else {
				Exception ex = new Exception(err);
				err = null;
				throw ex;
			}
		}
		err = null;
		ex1 = null;
		return val;
	}
	public int getSystemIOScript(final HQInteractiveObject io,
			final String name) {
		int index = -1;
		if (activeTimers > 0) {
			for (int i = 0; i < maxTimerScript; i++) {
				if (scriptTimers[i].exists()) {
					if (scriptTimers[i].getIo().equals(io)
							&& scriptTimers[i].getName().equalsIgnoreCase(
									name)) {
						index = i;
						break;
					}
				}
			}
		}
		return index;
	}
	/**
	 * Determines if an interactive object has a local variable set.
	 * @param ioid the IO's reference id
	 * @param name the name of the variable
	 * @return true if the IO has the variable; false otherwise
	 * @throws Exception if the IO doesn't exist
	 */
	public boolean hasLocalVariable(final int ioid, final String name)
			throws Exception {
		if (!Interactive.getInstance().hasIO(ioid)) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("IO ref id ");
			sb.append(ioid);
			sb.append(" does not exist.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		if (Interactive.getInstance().getIO(ioid) == null) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("IO ref id ");
			sb.append(ioid);
			sb.append(" does not exist.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		HQInteractiveObject io =
				(HQInteractiveObject) Interactive.getInstance().getIO(ioid);
		ScriptVariable lvar = io.getScript().getLocalVariable(name);
		boolean has = true;
		if (lvar == null) {
			has = false;
		}
		return has;
	}
	public void initEventStats() throws Exception {
		eventTotalCount = 0;
		for (int i = 0; i < Interactive.getInstance().getNumberIOs(); i++) {
			if (Interactive.getInstance().hasIO(i)) {
				HQInteractiveObject hio =
						(HQInteractiveObject) Interactive.getInstance()
								.getIO(i);
				hio.setStatCount(0);
				hio.setStatSent(0);
			}
		}
	}
	public void initScript(Scriptable<HQInteractiveObject> es) {
		es.clearAllowedEvents();
		if (es.getNumberOfLocalVars() > 0) {
			for (int i = 0; i < es.getNumberOfLocalVars(); i++) {
				es.getLocalVariable(i).setText(null);
				es.setLocalVariable(i, null);
			}
		}
		es.setNumberOfLocalVars(0);
		es.setMaster(null);

		for (int i = 0; i < HQGlobals.MAX_SCRIPTTIMERS; i++) {
			es.setTimer(i, 0);
		}
	}
	@Override
	public boolean isIOInGroup(final HQInteractiveObject io,
			final String group) {
		boolean val = false;
		for (int i = 0; i < io.getNumIOGroups(); i++) {
			if (group.equalsIgnoreCase(io.getIOGroup(i))) {
				val = true;
				break;
			}
		}
		return val;
	}
	/*
	private void makeSSEPARAMS(final String params) {
		for (int i = 0; i < SSEPARAMS.length; i++) {
			SSEPARAMS[i] = "";
		}
		if (params != null && params.length() > 0) {
			StringTokenizer token = new StringTokenizer(params, " ");
			int pos = 0;
			while (token.hasMoreTokens()) {
				if (pos < GlobalConsts.MAX_SSEPARAMS) {
					SSEPARAMS[pos] = token.nextToken();
				}
				pos++;
			}
		}
	}
	*/
	public int notifyIOEvent(final HQInteractiveObject io, final int msg,
			final Object[] params) throws Exception {
		int ret = HQGlobals.REFUSE;
		if (sendIOScriptEvent(io, msg, params, null) != HQGlobals.REFUSE) {
			switch (msg) {
			case HQGlobals.SM_17_DIE: {
				/*
				 * if (io && ValidIOAddress(io)) { io->infracolor.b = 1.f;
				 * io->infracolor.g = 0.f; io->infracolor.r = 0.f; }
				 */
			}
			}
			ret = HQGlobals.ACCEPT;
		}
		return ret;
	}
	@Override
	public void releaseAllGroups(final HQInteractiveObject io) {
		while (io.getNumIOGroups() > 0) {
			io.removeGroup(io.getIOGroup(0));
		}
		io.setNumIOGroups(0);
	}
	public void releaseScript(final Scriptable<HQInteractiveObject> event) {
		if (event != null) {
			if (event.getNumberOfLocalVars() > 0) {
				for (int i = 0; i < event.getNumberOfLocalVars(); i++) {
					event.getLocalVariable(i).setText(null);
					event.setLocalVariable(i, null);
				}
				event.setNumberOfLocalVars(0);
			}
		}
	}
	public void removeGroup(final HQInteractiveObject io, final String group) {
		if (io != null
				&& group != null) {
			io.removeGroup(group);
		}
	}
	public void reset(final HQInteractiveObject io, final int flags)
			throws Exception {
		// Release Script Local Variables
		if (io != null
				&& io.getScript() != null
				&& io.getScript().getNumberOfLocalVars() > 0) {
			for (int n = 0; n < io.getScript().getNumberOfLocalVars(); n++) {
				io.getScript().getLocalVariable(n).setText(null);
				io.getScript().setLocalVariable(n, null);
			}
			io.getScript().setNumberOfLocalVars(0);
		}
		// Release Script Over-Script Local Variables
		if (io != null
				&& io.getOverscript() != null
				&& io.getOverscript().getNumberOfLocalVars() > 0) {
			for (int n = 0; n < io.getOverscript().getNumberOfLocalVars(); n++) {
				io.getOverscript().getLocalVariable(n).setText(null);
				io.getOverscript().setLocalVariable(n, null);
			}
			io.getOverscript().setNumberOfLocalVars(0);
		}
		if (io != null
				&& !io.isScriptLoaded()) {
			resetObject(io, flags);
		}
	}
	public void resetAll(final int flags) throws Exception {
		for (int i = 0; i < Interactive.getInstance().getNumberIOs(); i++) {
			if (Interactive.getInstance().hasIO(i)) {
				HQInteractiveObject hio =
						(HQInteractiveObject) Interactive.getInstance().getIO(
								i);
				if (!hio.isScriptLoaded()) {
					reset(hio, flags);
				}
			}
		}
	}
	public void resetObject(final HQInteractiveObject io, final int flags)
			throws Exception {
		// Now go for Script INIT/RESET depending on Mode
		int num = io.getRefId();
		if (Interactive.getInstance().hasIO(num)) {
			HQInteractiveObject hio =
					(HQInteractiveObject) Interactive.getInstance().getIO(num);
			if (hio != null
					&& hio.getScript() != null) {
				hio.getScript().clearAllowedEvents();
				if (flags > 0) {
					sendScriptEvent(hio.getScript(), HQGlobals.SM_001_INIT,
							null,
							hio, null, 0);
				}

				if (Interactive.getInstance().hasIO(num)) {
					hio =
							(HQInteractiveObject) Interactive.getInstance()
									.getIO(
											num);
					setMainEvent(hio, "MAIN");
				}
			}
			// Do the same for Local Script
			if (Interactive.getInstance().hasIO(num)) {
				hio =
						(HQInteractiveObject) Interactive.getInstance().getIO(
								num);
				if (hio.getOverscript() != null) {
					hio.getOverscript().clearAllowedEvents();

					if (flags > 0) {
						sendScriptEvent(hio.getOverscript(),
								HQGlobals.SM_001_INIT,
								null, hio, null, 0);
					}
				}
			}
			// Sends InitEnd Event
			if (flags > 0) {
				if (Interactive.getInstance().hasIO(num)) {
					hio =
							(HQInteractiveObject) Interactive.getInstance()
									.getIO(
											num);
					if (hio != null
							&& hio.getScript() != null) {
						sendScriptEvent(hio.getScript(),
								HQGlobals.SM_33_INITEND,
								null, hio, null, 0);
					}
				}
				if (Interactive.getInstance().hasIO(num)) {
					hio =
							(HQInteractiveObject) Interactive.getInstance()
									.getIO(
											num);
					if (hio.getOverscript() != null) {
						hio.getOverscript().clearAllowedEvents();

						if (flags > 0) {
							sendScriptEvent(hio.getOverscript(),
									HQGlobals.SM_33_INITEND, null, hio, null, 0);
						}
					}
				}
			}
			if (Interactive.getInstance().hasIO(num)) {
				hio =
						(HQInteractiveObject) Interactive.getInstance().getIO(
								num);
				hio.removeGameFlag(HQGlobals.GFLAG_NEEDINIT);
			}
		}
	}
	public int sendInitScriptEvent(final HQInteractiveObject io)
			throws Exception {
		if (io == null) {
			return -1;
		}
		HQInteractiveObject oes = eventSender;
		eventSender = null;
		int num = io.getRefId();
		if (Interactive.getInstance().hasIO(num)) {
			// send script the init message
			if (Interactive.getInstance().getIO(num) != null) {
				HQInteractiveObject hio =
						(HQInteractiveObject) Interactive.getInstance().getIO(
								num);
				if (hio.getScript() != null) {
					GLOB = 0;
					sendScriptEvent(hio.getScript(), HQGlobals.SM_001_INIT,
							null,
							hio,
							null, 0);
				}
			}
			// send overscript the init message
			if (Interactive.getInstance().getIO(num) != null) {
				HQInteractiveObject hio =
						(HQInteractiveObject) Interactive.getInstance().getIO(
								num);
				if (hio.getOverscript() != null) {
					GLOB = 0;
					sendScriptEvent(hio.getOverscript(), HQGlobals.SM_001_INIT,
							null,
							hio, null, 0);
				}
			}
			// send script the init end message
			if (Interactive.getInstance().getIO(num) != null) {
				HQInteractiveObject hio =
						(HQInteractiveObject) Interactive.getInstance().getIO(
								num);
				if (hio.getScript() != null) {
					GLOB = 0;
					sendScriptEvent(hio.getScript(), HQGlobals.SM_33_INITEND,
							null,
							hio,
							null, 0);
				}
			}
			// send overscript the init end message
			if (Interactive.getInstance().getIO(num) != null) {
				HQInteractiveObject hio =
						(HQInteractiveObject) Interactive.getInstance().getIO(
								num);
				if (hio.getOverscript() != null) {
					GLOB = 0;
					sendScriptEvent(hio.getOverscript(),
							HQGlobals.SM_33_INITEND,
							null,
							hio, null, 0);
				}
			}
		}
		eventSender = oes;
		return HQGlobals.ACCEPT;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public int sendIOScriptEvent(final HQInteractiveObject io, final int msg,
			final Object[] params, final String eventname) throws Exception {
		// checks invalid IO
		if (io == null) {
			return -1;
		}
		int num = io.getRefId();

		if (Interactive.getInstance().hasIO(num)) {
			HQInteractiveObject oes = eventSender;

			if (msg == HQGlobals.SM_001_INIT
					|| msg == HQGlobals.SM_33_INITEND) {
				if (Interactive.getInstance().hasIO(num)) {
					HQInteractiveObject hio =
							(HQInteractiveObject) Interactive.getInstance()
									.getIO(
											num);
					sendIOScriptEventReverse(hio, msg, params, eventname);
					eventSender = oes;
				}
			}

			// if this IO only has a Local script, send event to it
			if (Interactive.getInstance().hasIO(num)) {
				HQInteractiveObject hio =
						(HQInteractiveObject) Interactive.getInstance().getIO(
								num);
				if (hio.getOverscript() == null) {
					GLOB = 0;
					int ret = sendScriptEvent(hio.getScript(), msg, params,
							hio,
							eventname, 0);
					eventSender = oes;
					return ret;
				}
			}

			// If this IO has a Global script send to Local (if exists)
			// then to Global if not overridden by Local
			if (Interactive.getInstance().hasIO(num)) {
				HQInteractiveObject hio =
						(HQInteractiveObject) Interactive.getInstance().getIO(
								num);
				int s = sendScriptEvent(hio.getOverscript(), msg, params, hio,
						eventname, 0);
				if (s != HQGlobals.REFUSE) {
					eventSender = oes;
					GLOB = 0;

					if (Interactive.getInstance().hasIO(num)) {
						hio = (HQInteractiveObject) Interactive.getInstance()
										.getIO(num);
						int ret = sendScriptEvent(hio.getScript(), msg, params,
								hio,
								eventname, 0);
						eventSender = oes;
						return ret;
					} else {
						return HQGlobals.REFUSE;
					}
				}
			}

			GLOB = 0;
		}

		// Refused further processing.
		return HQGlobals.REFUSE;
	}
	private int sendIOScriptEventReverse(final HQInteractiveObject io,
			final int msg, final Object[] params, final String eventname)
			throws Exception {
		// checks invalid IO
		if (io == null) {
			return -1;
		}
		int num = io.getRefId();
		if (Interactive.getInstance().hasIO(num)) {
			HQInteractiveObject hio =
					(HQInteractiveObject) Interactive.getInstance().getIO(
							num);
			// if this IO only has a Local script, send event to it
			if (hio.getOverscript() == null) {
				GLOB = 0;
				return sendScriptEvent(hio.getScript(), msg, params, hio,
						eventname, 0);
			}

			// If this IO has a Global script send to Local (if exists)
			// then to local if no overriden by Local
			if (Interactive.getInstance().hasIO(num)) {
				hio = (HQInteractiveObject) Interactive.getInstance().getIO(
							num);
				int s = sendScriptEvent(hio.getScript(), msg, params, hio,
							eventname, 0);
				if (s != HQGlobals.REFUSE) {
					GLOB = 0;

					if (Interactive.getInstance().hasIO(io.getRefId())) {
						return sendScriptEvent(io.getOverscript(), msg, params,
								io,
								eventname, 0);
					} else {
						return HQGlobals.REFUSE;
					}
				}
			}

			GLOB = 0;
		}
		// Refused further processing.
		return HQGlobals.REFUSE;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public int sendMsgToAllIO(final int msg, final Object[] dat)
			throws Exception {
		int ret = HQGlobals.ACCEPT;
		for (int i = 0; i < Interactive.getInstance().getNumberIOs(); i++) {
			if (Interactive.getInstance().hasIO(i)) {
				HQInteractiveObject io =
						(HQInteractiveObject) Interactive.getInstance()
								.getIO(i);
				if (sendIOScriptEvent(io, msg, dat, null) == HQGlobals.REFUSE) {
					ret = HQGlobals.REFUSE;
				}
			}
		}
		return ret;
	}
	public int sendScriptEvent(final Scriptable<HQInteractiveObject> event,
			final int msg, final Object[] params, final HQInteractiveObject io,
			final String evname, final int info) {
		if (io != null) {
			if (io.hasGameFlag(HQGlobals.GFLAG_MEGAHIDE)
					&& msg != HQGlobals.SM_43_RELOAD) {
				return HQGlobals.ACCEPT;
			}

			if (io.getShow() == HQGlobals.SHOW_FLAG_DESTROYED) { // destroyed
				return HQGlobals.ACCEPT;
			}
			io.setStatCount(io.getStatCount() + 1);

			if (io.hasIOFlag(HQGlobals.IO_06_FREEZESCRIPT)) {
				if (msg == HQGlobals.SM_41_LOAD) {
					return HQGlobals.ACCEPT;
				}
				return HQGlobals.REFUSE;
			}

			if (io.hasIOFlag(HQGlobals.IO_03_NPC)) {
				if (io.getNPCData().getBody() <= 0f
						&& msg != HQGlobals.SM_12_DEAD
						&& msg != HQGlobals.SM_17_DIE
						&& msg != HQGlobals.SM_255_EXECUTELINE
						&& msg != HQGlobals.SM_43_RELOAD
						&& msg != HQGlobals.SM_255_EXECUTELINE
						&& msg != HQGlobals.SM_28_INVENTORY2_OPEN
						&& msg != HQGlobals.SM_29_INVENTORY2_CLOSE) {
					return HQGlobals.ACCEPT;
				}
			}

			// change weapon if one breaks
			/*
			 * if (((io->ioflags & IO_FIX) || (io->ioflags & IO_ITEM)) && (msg
			 * == HQGlobals.SM_BREAK)) { ManageCasseDArme(io); }
			 */
		}
		Scriptable<HQInteractiveObject> script = null;
		event.getMaster();
		if (script == null) {
			script = event;
		}
		switch (msg) {
		case HQGlobals.SM_55_COLLIDE_NPC:
			if (script.hasAllowedEvent(HQGlobals.DISABLE_COLLIDE_NPC)) {
				return HQGlobals.REFUSE;
			}
			break;
		case HQGlobals.SM_10_CHAT:
			if (script.hasAllowedEvent(HQGlobals.DISABLE_CHAT)) {
				return HQGlobals.REFUSE;
			}
			break;
		case HQGlobals.SM_16_HIT:
			if (script.hasAllowedEvent(HQGlobals.DISABLE_HIT)) {
				return HQGlobals.REFUSE;
			}
			break;
		case HQGlobals.SM_28_INVENTORY2_OPEN:
			if (script.hasAllowedEvent(HQGlobals.DISABLE_INVENTORY2_OPEN)) {
				return HQGlobals.REFUSE;
			}
			break;
		case HQGlobals.SM_46_HEAR:
			if (script.hasAllowedEvent(HQGlobals.DISABLE_HEAR)) {
				return HQGlobals.REFUSE;
			}
			break;
		case HQGlobals.SM_23_UNDETECTPLAYER:
		case HQGlobals.SM_22_DETECTPLAYER:
			if (script.hasAllowedEvent(HQGlobals.DISABLE_DETECT)) {
				return HQGlobals.REFUSE;
			}
			break;
		case HQGlobals.SM_57_AGGRESSION:
			if (script.hasAllowedEvent(HQGlobals.DISABLE_AGGRESSION)) {
				return HQGlobals.REFUSE;
			}
			break;
		case HQGlobals.SM_008_MAIN:
			if (script.hasAllowedEvent(HQGlobals.DISABLE_MAIN)) {
				return HQGlobals.REFUSE;
			}
			break;
		case HQGlobals.SM_73_CURSORMODE:
			if (script.hasAllowedEvent(HQGlobals.DISABLE_CURSORMODE)) {
				return HQGlobals.REFUSE;
			}
			break;
		case HQGlobals.SM_74_EXPLORATIONMODE:
			if (script.hasAllowedEvent(HQGlobals.DISABLE_EXPLORATIONMODE)) {
				return HQGlobals.REFUSE;
			}
			break;
		case HQGlobals.SM_61_KEY_PRESSED:
			/*
			 * float dwCurrTime = ARX_TIME_Get(); if ((dwCurrTime -
			 * g_TimeStartCinemascope) < 3000) { return REFUSE; }
			 */
			return HQGlobals.REFUSE;
		}
		// set parameters on script that was sent
		if (params != null
				&& params.length > 0) {
			for (int i = 0; i < params.length; i += 2) {
				try {
					event.setLocalVariable((String) params[i], params[i + 1]);
				} catch (Exception ex) {
					JOGLErrorHandler.getInstance().fatalError(ex);
				}
			}
		}
		// makeSSEPARAMS(params);
		// switch message sent and react to it:
		try {
			switch (msg) {
			case HQGlobals.SM_001_INIT:
				script.onInit();
				break;
			case HQGlobals.SM_002_INVENTORYIN:
				script.onInventoryIn();
				break;
			case HQGlobals.SM_007_EQUIPOUT:
				script.onUnequip();
				break;
			case HQGlobals.SM_21_MOVE:
				// add IO to movement list
				HQMovement.getInstance().addIO(io.getRefId());
				// set map mode to play animation
				HQMap.getInstance().setMode(
						GlobalConsts.MAP_MODE_03_MOVE_ANIMATION);
				HQMap.getInstance().centerMapOnIO(io.getRefId());
				HQMap.getInstance().setCurrentAnimation(HQMap.ANIM_01_IO_MOVING);
				script.onMovement();
				break;
			case HQGlobals.SM_33_INITEND:
				script.onInitEnd();
				break;
			default:
				throw new Exception("No action defined for message " + msg);
			}
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}

		int ret = HQGlobals.ACCEPT;
		return ret;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setEventSender(final HQInteractiveObject newSender) {
		eventSender = newSender;
	}
	/**
	 * Sets a global variable.
	 * @param name the name of the global variable
	 * @param value the variable's value
	 * @throws Exception if an error occurs
	 */
	public void setGlobalVariable(final String name, final Object value)
			throws Exception {
		if (svar == null) {
			svar = new ScriptVariable[0];
		}
		boolean found = false;
		for (int i = 0; i < svar.length; i++) {
			ScriptVariable var = svar[i];
			if (var.getName().equals(name)) {
				// found the correct script variable
				if (var.getType() == RPGGlobals.TYPE_G_00_TEXT) {
					if (value instanceof String) {
						var.setText((String) value);
					} else if (value instanceof Float) {
						var.setText(((Float) value).toString());
					} else if (value instanceof Integer) {
						var.setText(((Integer) value).toString());
					} else if (value instanceof Long) {
						var.setText(((Long) value).toString());
					} else {
						PooledStringBuilder sb =
								StringBuilderPool.getInstance()
										.getStringBuilder();
						sb.append("Global variable ");
						sb.append(name);
						sb.append(" was passed new value of type ");
						sb.append(value.getClass().getCanonicalName());
						sb.append(". Only String, Float, Integer, or Long ");
						sb.append("allowed.");
						Exception ex = new Exception(sb.toString());
						sb.returnToPool();
						throw ex;
					}
				} else if (var.getType() == RPGGlobals.TYPE_G_01_FLOAT) {
					if (value instanceof String) {
						var.setFloatVal(Float.parseFloat((String) value));
					} else if (value instanceof Float) {
						var.setFloatVal((Float) value);
					} else if (value instanceof Integer) {
						var.setFloatVal((Integer) value);
					} else if (value instanceof Long) {
						var.setFloatVal((Long) value);
					} else {
						PooledStringBuilder sb =
								StringBuilderPool.getInstance()
										.getStringBuilder();
						sb.append("Global variable ");
						sb.append(name);
						sb.append(" was passed new value of type ");
						sb.append(value.getClass().getCanonicalName());
						sb.append(". Only String, Float, Integer, or Long ");
						sb.append("allowed.");
						Exception ex = new Exception(sb.toString());
						sb.returnToPool();
						throw ex;
					}
				} else if (var.getType() == RPGGlobals.TYPE_G_02_FLOAT_ARR) {
					if (value instanceof String) {
						var.setFloatArrayVal(Float.parseFloat((String) value));
					} else if (value instanceof Float) {
						var.setFloatArrayVal((Float) value);
					} else if (value instanceof float[]) {
						for (int c = 0; c < ((float[]) value).length; c++) {
							var.setFloatArrayVal(c, ((float[]) value)[c]);
						}
					} else if (value instanceof Integer) {
						var.setFloatArrayVal(((Float) value).floatValue());
					} else if (value instanceof int[]) {
						for (int c = 0; c < ((int[]) value).length; c++) {
							var.setFloatArrayVal(c, ((int[]) value)[c]);
						}
					} else if (value instanceof Long) {
						var.setFloatArrayVal(((Long) value).floatValue());
					} else if (value instanceof long[]) {
						for (int c = 0; c < ((long[]) value).length; c++) {
							var.setFloatArrayVal(c, ((long[]) value)[c]);
						}
					} else {
						PooledStringBuilder sb =
								StringBuilderPool.getInstance()
										.getStringBuilder();
						sb.append("Global variable ");
						sb.append(name);
						sb.append(" was passed new value of type ");
						sb.append(value.getClass().getCanonicalName());
						sb.append(". Only String, Float, float[], Integer, ");
						sb.append("int[], Long, or long[] allowed.");
						Exception ex = new Exception(sb.toString());
						sb.returnToPool();
						throw ex;
					}
				} else if (var.getType() == RPGGlobals.TYPE_G_03_INT) {
					if (value instanceof String) {
						var.setIntVal(Integer.parseInt((String) value));
					} else if (value instanceof Float) {
						var.setIntVal(((Float) value).intValue());
					} else if (value instanceof Integer) {
						var.setIntVal((Integer) value);
					} else if (value instanceof Long) {
						var.setIntVal(((Long) value).intValue());
					} else {
						PooledStringBuilder sb =
								StringBuilderPool.getInstance()
										.getStringBuilder();
						sb.append("Global variable ");
						sb.append(name);
						sb.append(" was passed new value of type ");
						sb.append(value.getClass().getCanonicalName());
						sb.append(". Only String, Float, Integer, or Long ");
						sb.append("allowed.");
						Exception ex = new Exception(sb.toString());
						sb.returnToPool();
						throw ex;
					}
				} else if (var.getType() == RPGGlobals.TYPE_G_04_INT_ARR) {
					if (value instanceof String) {
						var.setIntArrayVal(Integer.parseInt((String) value));
					} else if (value instanceof Float) {
						var.setIntArrayVal(((Float) value).intValue());
					} else if (value instanceof float[]) {
						for (int c = 0; c < ((float[]) value).length; c++) {
							var.setIntArrayVal(c, (int) ((float[]) value)[c]);
						}
					} else if (value instanceof Integer) {
						var.setIntArrayVal((Integer) value);
					} else if (value instanceof int[]) {
						for (int c = 0; c < ((int[]) value).length; c++) {
							var.setIntArrayVal(c, ((int[]) value)[c]);
						}
					} else if (value instanceof Long) {
						var.setIntArrayVal(((Long) value).intValue());
					} else if (value instanceof long[]) {
						for (int c = 0; c < ((long[]) value).length; c++) {
							var.setIntArrayVal(c, (int) ((long[]) value)[c]);
						}
					} else {
						PooledStringBuilder sb =
								StringBuilderPool.getInstance()
										.getStringBuilder();
						sb.append("Global variable ");
						sb.append(name);
						sb.append(" was passed new value of type ");
						sb.append(value.getClass().getCanonicalName());
						sb.append(". Only String, Float, float[], Integer, ");
						sb.append("int[], Long, or long[] allowed.");
						Exception ex = new Exception(sb.toString());
						sb.returnToPool();
						throw ex;
					}
				} else if (var.getType() == RPGGlobals.TYPE_G_05_LONG) {
					if (value instanceof String) {
						var.setLongVal(Long.parseLong((String) value));
					} else if (value instanceof Float) {
						var.setLongVal(((Float) value).longValue());
					} else if (value instanceof Integer) {
						var.setLongVal(((Integer) value).longValue());
					} else if (value instanceof Long) {
						var.setLongVal((Long) value);
					} else {
						PooledStringBuilder sb =
								StringBuilderPool.getInstance()
										.getStringBuilder();
						sb.append("Global variable ");
						sb.append(name);
						sb.append(" was passed new value of type ");
						sb.append(value.getClass().getCanonicalName());
						sb.append(". Only String, Float, Integer, or Long ");
						sb.append("allowed.");
						Exception ex = new Exception(sb.toString());
						sb.returnToPool();
						throw ex;
					}
				} else if (var.getType() == RPGGlobals.TYPE_G_06_LONG_ARR) {
					if (value instanceof String) {
						var.setLongArrayVal(Long.parseLong((String) value));
					} else if (value instanceof Float) {
						var.setLongArrayVal(((Float) value).longValue());
					} else if (value instanceof float[]) {
						for (int c = 0; c < ((float[]) value).length; c++) {
							var.setLongArrayVal(c, (long) ((float[]) value)[c]);
						}
					} else if (value instanceof Integer) {
						var.setLongArrayVal(((Integer) value).longValue());
					} else if (value instanceof int[]) {
						for (int c = 0; c < ((int[]) value).length; c++) {
							var.setLongArrayVal(c, ((int[]) value)[c]);
						}
					} else if (value instanceof Long) {
						var.setLongArrayVal((Long) value);
					} else if (value instanceof long[]) {
						for (int c = 0; c < ((long[]) value).length; c++) {
							var.setLongArrayVal(c, ((long[]) value)[c]);
						}
					} else {
						PooledStringBuilder sb =
								StringBuilderPool.getInstance()
										.getStringBuilder();
						sb.append("Global variable ");
						sb.append(name);
						sb.append(" was passed new value of type ");
						sb.append(value.getClass().getCanonicalName());
						sb.append(". Only String, Float, float[], Integer, ");
						sb.append("int[], Long, or long[] allowed.");
						Exception ex = new Exception(sb.toString());
						sb.returnToPool();
						throw ex;
					}
				}
				found = true;
				break;
			}
		}
		if (!found) {
			// create a new variable and add to the global array
			ScriptVariable var = null;
			if (value instanceof String) {
				var = 
					new ScriptVariable(name, RPGGlobals.TYPE_G_00_TEXT, value);
			} else if (value instanceof Float) {
				var = 
					new ScriptVariable(name, RPGGlobals.TYPE_G_01_FLOAT, value);
			} else if (value instanceof float[]) {
				var = new ScriptVariable(
						name, RPGGlobals.TYPE_G_02_FLOAT_ARR, value);
			} else if (value instanceof Integer) {
				var = new ScriptVariable(name, RPGGlobals.TYPE_G_03_INT, value);
			} else if (value instanceof int[]) {
				var = new ScriptVariable(
						name, RPGGlobals.TYPE_G_04_INT_ARR, value);
			} else if (value instanceof Long) {
				var = 
					new ScriptVariable(name, RPGGlobals.TYPE_G_05_LONG, value);
			} else if (value instanceof long[]) {
				var = new ScriptVariable(
						name, RPGGlobals.TYPE_G_06_LONG_ARR, value);
			} else {
				PooledStringBuilder sb =
						StringBuilderPool.getInstance().getStringBuilder();
				sb.append("Global variable ");
				sb.append(name);
				sb.append(" was passed new value of type ");
				sb.append(value.getClass().getCanonicalName());
				sb.append(". Only String, Integer, or Float allowed.");
				Exception ex = new Exception(sb.toString());
				sb.returnToPool();
				throw ex;
			}
			ScriptVariable[] dest = new ScriptVariable[svar.length + 1];
			System.arraycopy(svar, 0, dest, 0, svar.length);
			dest[svar.length] = var;
			svar = dest;
			dest = null;
		}
	}
	public void setMainEvent(final HQInteractiveObject io,
			final String newevent) {
		if (io == null) {
			return;
		}
		if ("MAIN".equalsIgnoreCase(newevent)) {
			io.setMainevent(null);
		} else {
			io.setMainevent(newevent);
		}
	}
	public void stackSendIOScriptEvent(final HQInteractiveObject io,
			final int msg, final Object[] params, final String eventname) {
		for (int i = 0; i < HQGlobals.MAX_EVENT_STACK; i++) {
			if (!eventstack[i].exists()) {
				if (params != null
						&& params.length > 0) {
					eventstack[i].setParams(params);
				} else {
					eventstack[i].setParams(null);
				}
				if (eventname != null
						&& eventname.length() > 0) {
					// eventstack[i].setEventname(params);
				} else {
					eventstack[i].setEventname(null);
				}

				eventstack[i].setSender(eventSender);
				eventstack[i].setIo(io);
				eventstack[i].setMsg(msg);
				eventstack[i].setExist(true);
				break;
			}
		}
	}
	public void stackSendMsgToAllNPCIO(final int msg, final Object[] dat)
			throws Exception {
		for (int i = 0; i < Interactive.getInstance().getNumberIOs(); i++) {
			if (Interactive.getInstance().hasIO(i)) {
				HQInteractiveObject hio =
						(HQInteractiveObject) Interactive.getInstance().getIO(
								i);
				if (hio.hasIOFlag(HQGlobals.IO_03_NPC)) {
					stackSendIOScriptEvent(hio, msg, dat, null);
				}
			}
		}
	}
	public void timerCheck() {
		if (activeTimers > 0) {
			for (int i = 0; i < maxTimerScript; i++) {
				HQScriptTimer st = scriptTimers[i];
				if (st.exists()) {
					if (st.hasFlag(1)) {
						if (!st.getIo().hasGameFlag(
								HQGlobals.GFLAG_ISINTREATZONE)) {
							while (st.getTim() + st.getMsecs() < Time
									.getInstance().getGameTime()) {
								st.setTim(st.getTim() + st.getMsecs());
							}
							continue;
						}
					}
					if (st.getTim() + st.getMsecs() < Time.getInstance()
							.getGameTime()) {
						Scriptable<HQInteractiveObject> es = st.getEs();
						HQInteractiveObject io = st.getIo();
						int pos = st.getPos();
						if (es != null) {
							if (st.getName().equalsIgnoreCase("_R_A_T_")) {
								// if (Manage_Specific_RAT_Timer(st))
								continue;
							}
						}

						if (st.getTimes() == 1) {
							timerClearByNum(i);
						} else {
							if (st.getTimes() != 0) {
								st.setTimes(st.getTimes() - 1);
							}
							st.setTim(st.getTim() + st.getMsecs());
						}

						if (es != null
								&& Interactive.getInstance().hasIO(
										io.getRefId())) {
							sendScriptEvent(es, HQGlobals.SM_255_EXECUTELINE,
									null,
									io, null, pos);
						}
					}
				}
			}
		}
	}
	@Override
	public void timerClearAll() {
		if (activeTimers > 0) {
			for (int i = 0; i < maxTimerScript; i++) {
				timerClearByNum(i);
			}
		}
		activeTimers = 0;
	}
	public void timerClearAllLocalsForIO(final HQInteractiveObject io) {
		for (int i = 0; i < maxTimerScript; i++) {
			if (scriptTimers[i].exists()) {
				if (scriptTimers[i].getIo().equals(io)
						&& scriptTimers[i].getEs().equals(io.getOverscript())) {
					timerClearByNum(i);
				}
			}
		}
	}
	public void timerClearByIO(final HQInteractiveObject io) {
		for (int i = 0; i < maxTimerScript; i++) {
			if (scriptTimers[i].exists()) {
				if (scriptTimers[i].getIo().equals(io)) {
					timerClearByNum(i);
				}
			}
		}
	}
	public void timerClearByNameAndIO(final String timername,
			final HQInteractiveObject io) {
		for (int i = 0; i < maxTimerScript; i++) {
			if (scriptTimers[i].exists()) {
				if (scriptTimers[i].getIo().equals(io)
						&& timername.equalsIgnoreCase(
								scriptTimers[i].getName())) {
					timerClearByNum(i);
				}
			}
		}
	}
	// *************************************************************************************
	// ARX_SCRIPT_Timer_ClearByNum
	// Clears a timer by its Index (long timer_idx) on the timers list
	// *************************************************************************************
	private void timerClearByNum(final int timeridx) {
		if (scriptTimers[timeridx].exists()) {
			scriptTimers[timeridx].setName(null);
			activeTimers--;
			scriptTimers[timeridx].setNamelength(0);
			scriptTimers[timeridx].setExists(false);
		}
	}
	@Override
	public void timerClearForIO(final HQInteractiveObject io) {
		for (int i = 0; i < maxTimerScript; i++) {
			if (scriptTimers[i].exists()) {
				if (scriptTimers[i].getIo().equals(io)) {
					timerClearByNum(i);
				}
			}
		}
	}
	// Checks if timer named texx exists. If so returns timer index else return
	// -1.
	private int timerExist(final String texx) {
		int index = -1;
		for (int i = 0; i < maxTimerScript; i++) {
			if (scriptTimers[i].exists()) {
				if (scriptTimers[i].getName() != null
						&& scriptTimers[i].getName().equalsIgnoreCase(texx)) {
					index = i;
					break;
				}
			}
		}

		return index;
	}
	@Override
	public void timerFirstInit(final int number) {
		if (number < 100) {
			maxTimerScript = 100;
		} else {
			maxTimerScript = number;
		}

		if (scriptTimers != null) {
			for (int i = 0; i < scriptTimers.length; i++) {
				scriptTimers[i] = null;
			}
			scriptTimers = null;
		}
		scriptTimers = new HQScriptTimer[maxTimerScript];
		for (int i = 0; i < scriptTimers.length; i++) {
			scriptTimers[i] = new HQScriptTimer();
		}
		activeTimers = 0;
	}
	// Generates a random name for an unnamed timer
	private String timerGetDefaultName() {
		int i = 1;
		String texx;

		while (true) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("TIMER_");
			sb.append(i);
			i++;

			if (timerExist(sb.toString()) == -1) {
				texx = sb.toString();
				sb.returnToPool();
				break;
			}
			sb.returnToPool();
		}
		return texx;
	}
	// *************************************************************************************
	// Get a free script timer
	// *************************************************************************************
	public int timerGetFree() {
		int index = -1;
		for (int i = 0; i < maxTimerScript; i++) {
			if (!scriptTimers[i].exists()) {
				index = i;
				break;
			}
		}
		return index;
	}
}
